package com.dragon.codefx.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.dragon.codefx.constant.DatabaseType;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 通用数据库连接管理器
 * 支持多种数据库：MySQL、SQLite、SQL Server、Oracle等
 * 使用Druid连接池实现连接缓存和管理
 */
public class ConnectionManager {
    // 数据源缓存，使用ConcurrentHashMap保证线程安全
    private static final ConcurrentHashMap<DataSourceKey, DruidDataSource> dataSourceCache = new ConcurrentHashMap<>();

    /**
     * 数据源键类，用于唯一标识一个数据源配置
     */
    private static class DataSourceKey {
        private final String jdbcUrl;    // JDBC连接URL
        private final String userName;   // 数据库用户名
        private final String password;  // 数据库密码

        public DataSourceKey(String jdbcUrl, String userName, String password) {
            this.jdbcUrl = jdbcUrl;
            this.userName = userName;
            this.password = password;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            DataSourceKey that = (DataSourceKey) o;
            return Objects.equals(jdbcUrl, that.jdbcUrl) &&
                    Objects.equals(userName, that.userName) &&
                    Objects.equals(password, that.password);
        }

        @Override
        public int hashCode() {
            return Objects.hash(jdbcUrl, userName, password);
        }
    }


    /**
     * 获取数据库连接
     *
     * @param jdbcUrl  JDBC连接URL
     * @param userName 数据库用户名
     * @param password 数据库密码
     * @return 可用的数据库连接
     * @throws RuntimeException 如果获取连接失败
     */
    public static Connection getConnection(String jdbcUrl, String userName, String password) {
        DruidDataSource dataSource = getDataSource(jdbcUrl, userName, password);

        try {
            // 首次尝试获取连接
            Connection connection = dataSource.getConnection();

            // 验证连接是否有效
            int validationTimeout = 5; // 验证超时时间(秒)
            if (connection != null && connection.isValid(validationTimeout)) {
                return connection;
            }

            // 如果连接无效，关闭并重新获取
            closeQuietly(connection);
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("获取数据库连接失败: " + jdbcUrl, e);
        }
    }

    /**
     * 从缓存中获取或创建数据源
     */
    private static DruidDataSource getDataSource(String jdbcUrl, String userName, String password) {
        DataSourceKey key = new DataSourceKey(jdbcUrl, userName, password);
        return dataSourceCache.computeIfAbsent(key, k -> createDataSource(k.jdbcUrl, k.userName, k.password));
    }

    /**
     * 创建新的Druid数据源
     */
    private static DruidDataSource createDataSource(String jdbcUrl, String userName, String password) {
        DatabaseType dbType = DatabaseType.fromJdbcUrl(jdbcUrl);
        DruidDataSource dataSource = new DruidDataSource();

        try {
            // 1. 设置基本连接参数
            dataSource.setUrl(jdbcUrl);
            dataSource.setUsername(userName);
            dataSource.setPassword(password);
            dataSource.setDriverClassName(dbType.getDriverClass());

            // 2. 配置连接池大小
            dataSource.setInitialSize(1);      // 初始连接数
            dataSource.setMinIdle(1);          // 最小空闲连接
            dataSource.setMaxActive(8);        // 最大活动连接
            dataSource.setMaxWait(3000);       // 获取连接最大等待时间(毫秒)

            // 3. 配置连接有效性检测
            dataSource.setTestOnBorrow(true);  // 借出连接时验证
            dataSource.setValidationQuery(dbType.getValidationQuery());
            dataSource.setTestWhileIdle(true); // 空闲时检测
            dataSource.setTimeBetweenEvictionRunsMillis(60000); // 检测间隔

            // 4. 配置连接泄漏检测
            dataSource.setRemoveAbandoned(true); // 打开泄露检测
            dataSource.setRemoveAbandonedTimeout(300); // 超时时间(秒)
            dataSource.setLogAbandoned(true);   // 记录泄露日志

            // 5. 初始化数据源
            dataSource.init();
            return dataSource;
        } catch (Exception e) {
            closeQuietly(dataSource);
            throw new RuntimeException("创建数据源失败: " + jdbcUrl, e);
        }
    }

    /**
     * 安静地关闭连接
     */
    private static void closeQuietly(Connection connection) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException ignored) {
                // 忽略关闭异常
            }
        }
    }

    /**
     * 安静地关闭数据源
     */
    private static void closeQuietly(DruidDataSource dataSource) {
        if (dataSource != null) {
            dataSource.close();
        }
    }

    /**
     * 关闭所有缓存的数据源
     */
    public static void closeAllDataSources() {
        dataSourceCache.values().forEach(ConnectionManager::closeQuietly);
        dataSourceCache.clear();
    }
}